using Azure;
using Essensoft.Paylink.WeChatPay.V3.Domain;
using Infrastructure;
using Infrastructure.Attribute;
using Infrastructure.Enums;
using Infrastructure.Extensions;
using JTZY.Common;
using JTZY.Infrastructure.CustomException;
using JTZY.Infrastructure.Enums;
using JTZY.Model.Brand;
using JTZY.Model.Business;
using JTZY.Model.Goods;
using JTZY.Model.Order;
using JTZY.Model.Order.Dto;
using JTZY.Model.Product;
using JTZY.Repository;
using JTZY.Service.Agent.IAgentService;
using JTZY.Service.Business.IBusinessService;
using JTZY.Service.Goods;
using JTZY.Service.Goods.IGoodsService;
using JTZY.Service.Order.IOrderService;
using JTZY.Service.Pay.IPayService;
using JTZY.ServiceCore.Services;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Asn1.X9;
using StackExchange.Redis;
using System;
using System.Linq.Expressions;
using static JTZY.Common.GlobalEnumVars;
using static Org.BouncyCastle.Crypto.Engines.SM2Engine;

namespace JTZY.Service.Order
{

    /// <summary>
    /// 退货单表Service业务层处理
    /// </summary>
    [AppService(ServiceType = typeof(ICorecmsbillaftersalesService), ServiceLifetime = LifeTime.Transient)]
    public class CorecmsbillaftersalesService : BaseService<Corecmsbillaftersales>, ICorecmsbillaftersalesService
    {
        //private readonly ICorecmsorderService _corecmsorderService;
        private readonly ICorecmsbillaftersalesitemService _corecmsbillaftersalesitemService;
        private readonly ICorecmsorderitemService _corecmsorderitemService;
        private readonly ICorecmsbillaftersalesimagesService _imageService;
        private readonly IBillaftersaledetailService _billaftersaledetailService;
        private readonly ICorecmsuserstockService _corecmsuserstockService;
        private readonly IServiceProvider _serviceProvider;
        private readonly ICorecmsbillrefundService _corecmsillrefundService;
        private readonly ICorecmsuserbalanceService _corecmsuserbalanceService;
        private readonly ICorecmsuserService _userService;
        private readonly IRedisOperationRepository _redisOperationRepository;

        public CorecmsbillaftersalesService(ICorecmsbillaftersalesitemService corecmsbillaftersalesitemService
            , ICorecmsorderitemService corecmsorderitemService
        //, ICorecmsorderService corecmsorderService
            , IServiceProvider serviceProvider
            , IBillaftersaledetailService billaftersaledetailService
            , ICorecmsuserstockService corecmsuserstockService
            , ICorecmsbillrefundService corecmsillrefundService
            , ICorecmsuserbalanceService corecmsuserbalanceService
            , ICorecmsuserService userService
            , IRedisOperationRepository redisOperationRepository
            , ICorecmsbillaftersalesimagesService imageService)
        {
            _corecmsbillaftersalesitemService = corecmsbillaftersalesitemService;
            _corecmsorderitemService = corecmsorderitemService;
            //_corecmsorderService = corecmsorderService;
            _imageService = imageService;
            _billaftersaledetailService = billaftersaledetailService;
            _corecmsuserstockService = corecmsuserstockService;
            _serviceProvider = serviceProvider;
            _corecmsillrefundService = corecmsillrefundService;
            _corecmsuserbalanceService = corecmsuserbalanceService;
            _userService = userService;
            _redisOperationRepository = redisOperationRepository;
        }

        /// <summary>
        /// 查询退货单表列表
        /// </summary>
        /// <param name="parm"></param>
        /// <returns></returns>
        public PagedInfo<CorecmsbillaftersalesDto> GetList(CorecmsbillaftersalesQueryDto parm)
        {
            var predicate = QueryExp(parm);

            var response = Queryable()
                //.LeftJoin<Corecmsuser>((it, custer) => it.UserId == custer.Id)
                //.Where((it, custer) => custer.ParentId == parm.userId)
                .Includes(x => x.User)
                .Includes(x => x.CorecmsbillaftersalesitemNav)
                //.Where((it) => it.User.ParentId == parm.userId)
                .Where(predicate.ToExpression()).OrderByDescending(it => new { it.CreateTime })
               .ToPage<Corecmsbillaftersales, CorecmsbillaftersalesDto>(parm);

            return response;
        }

        public PagedInfo<AfterProdDto> GetAfterStockList(AfterStockQueryDto parm)
        {
            var predicate = QueryStockExp(parm);

            var response = Queryable()
                .LeftJoin<Billaftersaledetail>((it, detail) => it.AftersalesId == detail.AftersalesId)
                .LeftJoin<Prodinfo>((it, detail, prod) => detail.SnCode == prod.SnCode)
                .LeftJoin<Corecmsproducts>((it, detail, prod, product) => prod.ProductId == product.Id)
                .LeftJoin<Corecmsgoods>((it, detail, prod, product, good) => prod.GoodsId == good.Id)
                .LeftJoin<Corecmsbrand>((it, detail, prod, product, good, brand) => good.BrandId == brand.Id)
                .Where(predicate.ToExpression())
                .WhereIF(parm.Status.HasValue && parm.Status == 1, (it, detail, prod, product, good, brand) => prod.Status == parm.Status)
                .WhereIF(parm.Status.HasValue && parm.Status == 2, (it, detail, prod, product, good, brand) => prod.Status == 3 || prod.Status == 2)
                .WhereIF(!string.IsNullOrEmpty(parm.filter), (it, detail, prod, product, good, brand) => prod.SnCode == parm.filter || product.SkuName.Contains(parm.filter))
                .OrderByDescending(it => new { it.CreateTime })
                .Select((it, detail, prod, product, good, brand) => new AfterProdDto()
                {
                    AftersalesId = it.OldaftersalesId,
                    SnCode = prod.SnCode,
                    ProdctDate = prod.ProdctDate,
                    Addon = product.SkuName,
                    CreateTime = it.CreateTime,
                    ImageUrl = product.Images,
                    Status = prod.Status,
                    Memo = prod.Status == 1 ? "待发货至[质得]" : prod.Status == 2 ? "待[质得]签收" : "已被[质得]签收",
                    BrandName = brand.Name,
                }).ToPage<AfterProdDto>(parm);

            return response;
        }


        /// <summary>
        /// 获取详情
        /// </summary>
        /// <param name="AftersalesId"></param>
        /// <returns></returns>
        public Corecmsbillaftersales GetInfo(string AftersalesId)
        {
            var response = Queryable()
                                .Includes(x => x.CorecmsbillaftersalesitemNav)
                .Includes(x => x.Images)

                .Where(x => x.AftersalesId == AftersalesId)
                .First();

            return response;
        }

        /// <summary>
        /// 添加退货单表
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public Corecmsbillaftersales AddCorecmsbillaftersales(Corecmsbillaftersales model)
        {
            return Insertable(model).ExecuteReturnEntity();
        }

        /// <summary>
        /// 导出退货单表
        /// </summary>
        /// <param name="parm"></param>
        /// <returns></returns>
        public PagedInfo<CorecmsbillaftersalesExDto> ExportList(CorecmsbillaftersalesQueryDto parm)
        {
            var predicate = QueryExp(parm);

            var response = Queryable()
                .LeftJoin<Corecmsbillaftersalesitem>((it,oi)=>it.AftersalesId==oi.AftersalesId)
                .LeftJoin<Corecmsuser>((it, oi,u) => it.UserId == u.Id)
                .Where(predicate.ToExpression())
                .Select((it, oi, u) => new CorecmsbillaftersalesExDto()
                {
                    AftersalesId=it.AftersalesId,
                    OrderId=it.OrderId,
                    CreateTime=it.CreateTime,
                    UserName=u.UserName,
                    PayStatus = it.PayStatus == 1 ? "未支付":"已支付",
                    PayTime=it.PayTime,
                    ReMethod=it.ReMethod=="0"? "邮寄退货": "上门退货",
                    Addon=oi.Addon,
                    Sn=oi.Sn,
                    Nums=oi.Nums,
                    Amount = oi.Amount,
                    Status=it.Status,
                    AfterProgress=it.AfterProgress
                }, true)
                .ToPage(parm);

            return response;
        }

        public WebApiCallBack CancelAfterSales(Corecmsbillaftersales model)
        {
            var jm = new WebApiCallBack();
            var after = Queryable().Where(x => x.AftersalesId == model.AftersalesId).First();
            //if (after.Status != (int)BillAftersalesStatus.WaitAudit)
            //{
            //    jm.status = false;
            //    jm.msg = "此状态下不可取消";
            //    return jm;
            //}
            if (after.RetReasons == "2")
            {
                if (after.AfterProgress == 6 || after.AfterProgress == 4 || after.AfterProgress == 5 || after.AfterProgress == 3)
                {
                    jm.status = false;
                    jm.msg = "此状态下不可取消";
                    return jm;
                }

                var details = Context.Queryable<Billaftersaledetail>()
                    .Where(x => x.AftersalesId == model.AftersalesId)
                    .ToList();

                var items = Context.Queryable<Corecmsbillaftersalesitem>()
                    .Where(x => x.AftersalesId == model.AftersalesId)
                    .ToList();

                var products = items.Select(x => x.ProductId).ToList();

                var userStockList = Context.Queryable<Corecmsuserstock>().Where(p => p.UserId == model.UserId && products.Contains(p.ProductId)).ToList();
                var result = UseTran(() =>
                {
                    details.ForEach(detail =>
                    {
                        Context.Updateable<Prodinfo>().SetColumns(it => new Prodinfo { Status = 2 }).Where(it => it.SnCode == detail.SnCode).ExecuteCommand();
                    });

                    items.ForEach(item =>
                    {
                        var us = userStockList.Find(us => us.ProductId == item.ProductId);
                        if (us != null)
                        {
                            us.Stock += item.Nums;
                            us.SaleStock += item.Nums;
                        }
                    });

                    Context.Updateable<Corecmsuserstock>(userStockList).WhereColumns(it => new { it.Id }).UpdateColumns(it => new { it.Stock, it.SaleStock }).ExecuteCommand();

                    Update(w => w.AftersalesId == after.AftersalesId,
                    it => new Corecmsbillaftersales() { Status = (int)BillAftersalesStatus.Cancel, AfterProgress = -1, UpdateTime = DateTime.Now });
                });

                jm.status = result.IsSuccess;
                jm.msg = result.ErrorMessage;
                jm.data = model;

            }
            else
            {
                if (after.AfterProgress == 6 || after.AfterProgress == 4 || after.AfterProgress == 5 || after.AfterProgress == 3)
                {
                    jm.status = false;
                    jm.msg = "此状态下不可取消";
                    return jm;
                }


                int res = Update(w => w.AftersalesId == after.AftersalesId,
                    it => new Corecmsbillaftersales() { Status = (int)BillAftersalesStatus.Cancel, AfterProgress = -1, UpdateTime = DateTime.Now });
                if (res > 0)
                {
                    jm.status = true;
                    jm.data = model;
                }
                else
                {
                    jm.status = false;
                    jm.msg = "取消失败" +
                        "";
                }
            }
            return jm;
        }

        public WebApiCallBack NoAuditAfterSales(Corecmsbillaftersales model)
        {
            var jm = new WebApiCallBack();
            var after = Queryable().Where(x => x.AftersalesId == model.AftersalesId).First();
            if (after.Status != (int)BillAftersalesStatus.WaitAudit)
            {
                jm.status = false;
                jm.msg = "此状态下不可拒绝";
                return jm;
            }
            int res = Update(w => w.AftersalesId == after.AftersalesId,
                it => new Corecmsbillaftersales()
                {
                    Status = (int)BillAftersalesStatus.Refuse,
                    AfterProgress = -1,
                    Mark = model.Mark,
                    UpdateTime = DateTime.Now
                });
            if (res > 0)
            {
                jm.status = true;
                jm.data = model;

            }
            else
            {
                jm.status = false;
                jm.msg = "取消失败";
            }
            return jm;
        }

        public async Task<WebApiCallBack> Take(Corecmsbillaftersales modal, long userId)
        {
            var jm = new WebApiCallBack();
            if (IsBetween0And9AM()&& modal.RetReasons != "3")
            {
                DateTime dt = DateTime.Now;
                await _redisOperationRepository.SortedSetAddAsync(RedisMessageQueueKey.SmsQueue, "延时退款测试", new DateTime(dt.Year, dt.Month, dt.Day, 9, dt.Minute, dt.Second));
                jm.msg = "请8点后处理，系统这个时段正在结算，有可能退款不成功";
                return jm;
            }

            var result = UseTran(() =>
            {
                var container = _serviceProvider.CreateScope();

                var reshipServices = container.ServiceProvider.GetService<ICorecmsbillreshipService>();
                var order = Queryable().Where(o => o.AftersalesId == modal.AftersalesId && (o.AfterProgress == 2 || o.AfterProgress == 1)).First();
                if (order == null) throw new CustomException("售后订单不存在");
                if(order.AfterProgress==3) throw new CustomException("售后订单已完成");
                var orderItemList = Context.Queryable<Corecmsbillaftersalesitem>().Where(p => p.AftersalesId == modal.AftersalesId).ToList();
                var details = Context.Queryable<Billaftersaledetail>().Where(d => d.AftersalesId == modal.AftersalesId).ToList();
                var productIds = orderItemList.Select(oi => oi.ProductId).ToList();
                order.ReceiveTime = DateTime.Now;

                //换货
                if (modal.RetReasons == "3")
                {
                    //修改为待商家发货
                    order.AfterProgress = 5;
                }
                else
                {

                    //直接完成
                    order.AfterProgress = 3;

                    //非质量退货 需要更改库存
                    if (modal.RetReasons != "1")
                    {
                        var userStockList = Context.Queryable<Corecmsuserstock>().Where(p => p.UserId == userId && productIds.Contains(p.ProductId)).ToList();
                        foreach (var product in orderItemList)
                        {
                            var us = userStockList.Find(us => us.ProductId == product.ProductId);
                            if (us != null)
                            {
                                us.Stock = (us.Stock.HasValue ? us.Stock + product.Nums : product.Nums);
                                us.SaleStock = (us.SaleStock.HasValue ? us.SaleStock + product.Nums : product.Nums); //us.SaleStock + product.Nums;
                                us.SaleQty = (us.SaleQty.HasValue ? us.SaleQty + product.Nums : product.Nums);
                            }
                        }
                        Context.Updateable<Corecmsuserstock>(userStockList).UpdateColumns(it => new { it.Stock, it.SaleStock, it.SaleQty }).ExecuteCommand(); ;

                    }
                }


                var flowList = new List<StockFlowItem>();
                var dt = DateTime.Now;
                //更新产品所属关系
                var codes = details.Select(d => d.SnCode).ToList();
                var ProdinfoList = Context.Queryable<Prodinfo>().Where(d => codes.Contains(d.SnCode)).ToList();
                foreach (var prod in ProdinfoList)
                {
                    var product = orderItemList.Where(i => i.ProductId == prod.ProductId).FirstOrDefault();

                    prod.UserId = userId;
                    prod.IsReturn = (modal.RetReasons == "1" || modal.RetReasons == "3" ? 1 : 0);
                    prod.Status = 1;//入库

                    var flow = new StockFlowItem();
                    flow.UserId = userId;
                    flow.CreateTime = dt;
                    flow.SheetNo = order.AftersalesId;
                    flow.SnCode = prod.SnCode;
                    flow.ProductId = prod.ProductId;
                    flow.DbNo = "+";
                    flow.OrderType = 2;
                    flow.Price = product.Price;

                    flowList.Add(flow);

                }

                //商品所属代理更改
                Context.Updateable<Prodinfo>(ProdinfoList).UpdateColumns(it => new { it.UserId, it.IsReturn, it.Status }).ExecuteCommand(); ;

                //写入库明细
                Context.Insertable<StockFlowItem>(flowList).ExecuteCommand();

                int updateRes = Update(u => u.AftersalesId == modal.AftersalesId, it => new Corecmsbillaftersales()
                {
                    AfterProgress = order.AfterProgress,
                    //ConfirmStatus = 2,
                    //ConfirmTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                    ReceiveTime = order.ReceiveTime
                });

                //更新退货状态
                reshipServices.Update(it => it.AftersalesId == modal.AftersalesId, w => new Corecmsbillreship { Status = (int)BillReshipStatus.已收退货 });

                if (updateRes > 0 && (modal.RetReasons == "1" || modal.RetReasons == "3"))
                {
                    var afterSalesNew = JsonConvert.DeserializeObject<Corecmsbillaftersales>(JsonConvert.SerializeObject(order));
                    afterSalesNew.AftersalesId = CommonHelper.GetSerialNumberType((int)SerialNumberType.售后单编号);
                    afterSalesNew.UserId = userId;
                    afterSalesNew.Status = (int)BillAftersalesStatus.Success;
                    afterSalesNew.CreateTime = DateTime.Now;
                    afterSalesNew.SourceType = "1";
                    afterSalesNew.AfterProgress = 5;
                    afterSalesNew.RetReasons = "1";
                    afterSalesNew.OldaftersalesId = order.AftersalesId;
                    Context.Insertable<Corecmsbillaftersales>(afterSalesNew).ExecuteCommand(); ;


                    var orderItemListNew = JsonConvert.DeserializeObject<List<Corecmsbillaftersalesitem>>(JsonConvert.SerializeObject(orderItemList));
                    orderItemListNew.ForEach(item =>
                    {
                        item.AftersalesId = afterSalesNew.AftersalesId;
                        item.Id = 0;
                    });
                    Context.Insertable<Corecmsbillaftersalesitem>(orderItemListNew).ExecuteCommand(); ;

                    var detailsNew = JsonConvert.DeserializeObject<List<Billaftersaledetail>>(JsonConvert.SerializeObject(details));
                    detailsNew.ForEach(item =>
                    {
                        item.AftersalesId = afterSalesNew.AftersalesId;
                        item.Id = 0;
                    });
                    Context.Insertable<Billaftersaledetail>(detailsNew).ExecuteCommand();

                    var images = _imageService.GetList(img => img.AftersalesId == order.AftersalesId);
                    if (images != null && images.Count > 0)
                    {
                        foreach (var image in images)
                        {
                            image.AftersalesId = afterSalesNew.AftersalesId;
                        }

                        _imageService.InsertRange(images);
                    }

                    reshipServices.ToAdd(userId, order.OrderId, afterSalesNew, orderItemListNew, detailsNew, "1");
                }

                if (updateRes > 0 && modal.RetReasons != "3")
                {
                    //需要退款
                    var refund = _corecmsillrefundService.Queryable().Where(p => p.AftersalesId == modal.AftersalesId && p.Status == (int)BillRefundStatus.STATUS_NOREFUND).First();
                    if (refund != null)
                    {
                        //await _corecmsillrefundService.PaymentRefund(refund.RefundId);
                    }

                    //返还销售提成
                    var list = _corecmsuserbalanceService.Queryable().Where(b => b.SourceId == refund.SourceId && b.Type == (int)UserBalanceSourceTypes.Agent).ToList();
                    if (list != null)
                    {
                        var user = _userService.GetById(userId);
                        var returnList = new List<Corecmsuserbalance>();
                        decimal balanceMoney = user.Balance;
                        foreach (var item in orderItemList)
                        {
                            var product = list.Find(p => p.ProductId == item.ProductId);
                            if (product != null)
                            {
                                decimal price = product.Money / product.Nums.Value;
                                decimal money = price * item.Nums;
                                user.Balance = user.Balance - money;
                                var balanceModel = new Corecmsuserbalance();
                                balanceModel.UserId = userId;
                                balanceModel.Type = (int)UserBalanceSourceTypes.Return;
                                balanceModel.Money = -money;
                                balanceModel.Balance = user.Balance;
                                balanceModel.SourceId = order.AftersalesId;
                                balanceModel.OrderId = order.OrderId;
                                balanceModel.Memo = "退货";
                                balanceModel.CreateTime = DateTime.Now;
                                balanceModel.ProductId = product.ProductId;
                                balanceModel.Addon = product.Addon;
                                balanceModel.ImageUrl = product.ImageUrl;
                                balanceModel.Nums = product.Nums;
                                returnList.Add(balanceModel);
                            }
                        }
                        //写入余额明细
                        _corecmsuserbalanceService.InsertRange(returnList);
                        //更新明显
                        var updateNum = _userService.Update(it => it.Id == userId && it.Balance == balanceMoney, u => new Corecmsuser()
                        {
                            Balance = user.Balance,
                        });
                        if (updateNum <= 0)
                        {
                            throw new CustomException("售后订单收货失败，请联系厂商");
                        }
                    }

                }

            });

            if (result.IsSuccess)
            {
                if (modal.RetReasons != "3")
                {
                    //需要退款
                    var refund = _corecmsillrefundService.Queryable().Where(p => p.AftersalesId == modal.AftersalesId && p.Status == (int)BillRefundStatus.STATUS_NOREFUND).First();
                    if (refund != null)
                    {
                        await _corecmsillrefundService.PaymentRefund(refund.RefundId);
                    }
                    try
                    {
                        if (IsBetween0And9AM())
                        {
                            DateTime dt = DateTime.Now;
                            await _redisOperationRepository.SortedSetAddAsync(RedisMessageQueueKey.SmsQueue, "延时退款测试", new DateTime(dt.Year, dt.Month, dt.Day, 9, dt.Minute, dt.Second));
                        }
                    }
                    catch{ }
                }
            }
            jm.status = result.IsSuccess;
            jm.msg = result.ErrorMessage;
            return jm;
        }

        public async Task<WebApiCallBack> Refund(Corecmsbillaftersales modal, long userId)
        {
            var order = Queryable().Where(o => o.AftersalesId == modal.AftersalesId && (o.AfterProgress == 5)).First();
            if (order == null) throw new CustomException("不是有效的售后订单");

            var jm = new WebApiCallBack();


            var result = UseTran(() =>
            {
                var orderItemList = Context.Queryable<Corecmsbillaftersalesitem>().Where(p => p.AftersalesId == modal.AftersalesId).ToList();
                if (orderItemList == null || orderItemList.Count == 0)
                {
                    if (order == null) throw new CustomException("不是有效的售后订单");

                }
                decimal refundAmount = 0;
                orderItemList.ForEach((item) =>
                {
                    refundAmount += item.Amount;
                });

                //更改为质量退货
                int updateRes = Update(u => u.AftersalesId == order.AftersalesId, it => new Corecmsbillaftersales()
                {
                    AfterProgress = 3,
                    UpdateTime = DateTime.Now,
                    RetReasons = "1",
                    RefundAmount = refundAmount,
                });

                if (updateRes <= 0)
                {
                    throw new CustomException("售后订单退款失败，请联系厂商");
                }

                var billRefund = new Corecmsbillrefund();
                billRefund.RefundId = CommonHelper.GetSerialNumberType((int)SerialNumberType.退款单编号);
                billRefund.AftersalesId = order.AftersalesId;
                billRefund.Money = refundAmount;
                billRefund.UserId = order.UserId;
                billRefund.SourceId = order.OrderId;
                billRefund.Type = 1;
                billRefund.SourceType = "0";

                using var container = _serviceProvider.CreateScope();
                var _billPaymentsServices = container.ServiceProvider.GetService<ICorecmsbillpaymentsService>();

                //取支付成功的支付单号
                var paymentsInfo = _billPaymentsServices.Queryable().Where(p => p.SourceId == order.OrderId && p.Type == 1 && p.Status == (int)BillPaymentsStatus.Payed).First();
                if (paymentsInfo != null)
                {
                    billRefund.PaymentCode = paymentsInfo.PaymentCode;
                    billRefund.TradeNo = paymentsInfo.TradeNo;
                }

                billRefund.Status = (int)BillRefundStatus.STATUS_NOREFUND;
                billRefund.CreateTime = DateTime.Now;
                billRefund.StoreId = order.StoreId;
                //Insert(billRefund);
                int refundInt = _corecmsillrefundService.Insert(billRefund);
                if (refundInt <= 0)
                {
                    throw new CustomException("售后订单退款失败，请联系厂商");
                }

                //返还销售提成
                var list = _corecmsuserbalanceService.Queryable().Where(b => b.SourceId == order.OrderId && b.Type == (int)UserBalanceSourceTypes.Agent).ToList();
                if (list != null)
                {
                    var user = _userService.GetById(userId);
                    var returnList = new List<Corecmsuserbalance>();
                    decimal balanceMoney = user.Balance;
                    foreach (var item in orderItemList)
                    {
                        var product = list.Find(p => p.ProductId == item.ProductId);
                        if (product != null)
                        {
                            decimal price = product.Money / product.Nums.Value;
                            decimal money = price * item.Nums;
                            user.Balance = user.Balance - money;
                            var balanceModel = new Corecmsuserbalance();
                            balanceModel.UserId = userId;
                            balanceModel.Type = (int)UserBalanceSourceTypes.Return;
                            balanceModel.Money = -money;
                            balanceModel.Balance = user.Balance;
                            balanceModel.SourceId = order.AftersalesId;
                            balanceModel.OrderId = order.OrderId;
                            balanceModel.Memo = "退货";
                            balanceModel.CreateTime = DateTime.Now;
                            balanceModel.ProductId = product.ProductId;
                            balanceModel.Addon = product.Addon;
                            balanceModel.ImageUrl = product.ImageUrl;
                            balanceModel.Nums = product.Nums;
                            returnList.Add(balanceModel);
                        }
                    }
                    //写入余额明细
                    _corecmsuserbalanceService.InsertRange(returnList);
                    //更新明显
                    var updateNum = _userService.Update(it => it.Id == userId && it.Balance == balanceMoney, u => new Corecmsuser()
                    {
                        Balance = user.Balance,
                    });
                    if (updateNum <= 0)
                    {
                        throw new CustomException("售后订单收货失败，请联系厂商");
                    }
                }

            });

            if (result.IsSuccess)
            {

                //需要退款
                var refund = _corecmsillrefundService.Queryable().Where(p => p.AftersalesId == modal.AftersalesId && p.Status == (int)BillRefundStatus.STATUS_NOREFUND).First();
                if (refund != null)
                {
                    await _corecmsillrefundService.PaymentRefund(refund.RefundId);
                }

            }
            jm.status = result.IsSuccess;
            jm.msg = result.ErrorMessage;
            return jm;
        }


        public async Task<WebApiCallBack> Ship(Corecmsbillaftersales modal, long userId)
        {
            var jm = new WebApiCallBack();
            var saleList = new List<Model.Order.Dto.SaleInfo>();
            var result = UseTran(() =>
            {
                var order = Queryable().Where(o => o.AftersalesId == modal.AftersalesId).First();
                if (order == null) throw new CustomException("订单不存在");
                order.AfterProgress = 2;//商品收货完成
                order.ShipTime = DateTime.Now;
                //减库存 
                var orderItemList = Context.Queryable<Corecmsbillaftersalesitem>().Where(p => p.AftersalesId == modal.AftersalesId).ToList();
                var details = Context.Queryable<Exchangedetail>().Where(d => d.AftersalesId == modal.AftersalesId).ToList();
                var productIds = orderItemList.Select(oi => oi.ProductId).ToList();

                var userStockList = Context.Queryable<Corecmsuserstock>().Where(p => p.UserId == userId && productIds.Contains(p.ProductId)).ToList();

                foreach (var product in orderItemList)
                {
                    var us = userStockList.Find(us => us.ProductId == product.ProductId);
                    if (us != null)
                    {
                        //质量退货,发货
                        if (order.RetReasons == "3")
                        {
                            us.Stock = us.Stock - product.Nums;
                            us.SaleStock = us.SaleStock - product.Nums;

                        }
                    }
                }
                Context.Updateable<Corecmsuserstock>(userStockList).UpdateColumns(it => new { it.Stock, it.SaleStock }).ExecuteCommand();

                var flowList = new List<StockFlowItem>();
                var dt = DateTime.Now;
                //更新产品所属关系
                var codes = details.Select(d => d.SnCode).ToList();
                var ProdinfoList = Context.Queryable<Prodinfo>().Where(d => codes.Contains(d.SnCode)).ToList();
                foreach (var prod in ProdinfoList)
                {
                    var product = orderItemList.Where(i => i.ProductId == prod.ProductId).FirstOrDefault();
                    prod.UserId = order.UserId;
                    prod.Status = 2;

                    var flow = new StockFlowItem();
                    flow.UserId = order.UserId;
                    flow.CreateTime = dt;
                    flow.SheetNo = order.AftersalesId;
                    flow.SnCode = prod.SnCode;
                    flow.ProductId = prod.ProductId;
                    flow.DbNo = "-";
                    flow.OrderType = 0;
                    flow.Price = product.Price;

                    flowList.Add(flow);
                    saleList.Add(new Model.Order.Dto.SaleInfo { snCode = prod.SnCode, saleDate = dt });
                }
                Context.Updateable<Prodinfo>(ProdinfoList).UpdateColumns(it => new { it.UserId, }).ExecuteCommand(); ;

                //写入库明细
                Context.Insertable<StockFlowItem>(flowList).ExecuteCommand();

                Update(u => u.AftersalesId == modal.AftersalesId, it => new Corecmsbillaftersales()
                {
                    ShipTime = order.ShipTime,
                    AfterProgress = order.AfterProgress,
                    //ConfirmStatus = 2,
                    //ConfirmTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                });

            });
            if (result.IsSuccess)
            {
                try
                {
                    foreach (var item in saleList)
                    {
                        await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.PushSaleDateTime, JsonConvert.SerializeObject(item));
                    }
                }
                catch { }
            }

            jm.status = result.IsSuccess;
            jm.msg = result.ErrorMessage;
            return jm;
        }

        /// <summary>
        /// 打包发货
        /// </summary>
        /// <param name="modal"></param>
        /// <returns></returns>
        public WebApiCallBack Pack(OrderPackDto modal)
        {
            var jm = new WebApiCallBack();

            var result = UseTran(() =>
            {
                var afterSales = Queryable().Where(o => o.AftersalesId == modal.afterSalesId && o.AfterProgress == 5).First();
                if (afterSales == null)
                {
                    jm.status = false;
                    jm.msg = "订单不存在";
                    return;
                }
                //order.Status = 4;//商品已打包

                var orderItems = Context.Queryable<Corecmsorderitem>().Where(p => p.OrderId == modal.orderId).ToList();

                if (orderItems == null)
                {
                    jm.status = false;
                    jm.msg = "订单不存在";
                    return;
                }

                if (modal.list == null || modal.list.Count <= 0) 
                {
                    jm.status = false;
                    jm.msg = "您提交换货商品信息";
                    return;
                }

                //减库存 
                var orderItemList = Context.Queryable<Corecmsbillaftersalesitem>().Where(p => p.AftersalesId == modal.afterSalesId).ToList();

                var productIds = orderItemList.Select(oi => oi.ProductId).ToList();
                var afterCodes = Context.Queryable<Billaftersaledetail>().Where(p => p.AftersalesId == modal.afterSalesId).Select(d => d.SnCode).ToList();

                var userStockList = Context.Queryable<Corecmsuserstock>().Where(p => p.UserId == modal.userId && productIds.Contains(p.ProductId)).ToList();

                foreach (var product in orderItemList)
                {
                    var us = userStockList.Find(us => us.ProductId == product.ProductId);
                    if (us != null)
                    {
                        //质量退货,发货
                        if (afterSales.RetReasons == "3")
                        {
                            us.Stock = us.Stock - product.Nums;
                            us.SaleStock = us.SaleStock - product.Nums;

                        }
                    }
                }
                Context.Updateable<Corecmsuserstock>(userStockList).UpdateColumns(it => new { it.Stock, it.SaleStock }).ExecuteCommand();

                using var container = _serviceProvider.CreateScope();
                //var orderServices = container.ServiceProvider.GetService<ICorecmsorderService>();
                modal.orderId = afterSales.OrderId;
                modal.list.ForEach(item =>
                {
                    item.OrderId = afterSales.OrderId;
                });
                Context.Deleteable<Orderdetail>().Where(d => d.OrderId == modal.orderId && afterCodes.Contains(d.SnCode)).ExecuteCommand();
                Context.Insertable<Orderdetail>(modal.list).ExecuteCommand();

                var Exchangedetails = new List<Exchangedetail>();
                orderItems.ForEach(item =>
                {

                    List<string> l = modal.list.Where(d => d.ProductId == item.ProductId).Select(d => d.SnCode).ToList();

                    item.SnCodes = JsonConvert.SerializeObject(l);

                    //_orderItemServices.Update(u => u.Id == item.Id, it => new Corecmsorderitem() { SnCodes = item.SnCodes });
                    Context.Updateable<Corecmsorderitem>().SetColumns(it => new Corecmsorderitem() { SnCodes = item.SnCodes, UpdateTime = DateTime.Now, }).Where(u => u.OrderId == modal.orderId && u.ProductId == item.ProductId).RemoveDataCache().ExecuteCommand();
                });

                var flowList = new List<StockFlowItem>();
                var dt = DateTime.Now;
                //更新产品所属关系
                var codes = modal.list.Select(d => d.SnCode).ToList();
                var ProdinfoList = Context.Queryable<Prodinfo>().Where(d => codes.Contains(d.SnCode)).ToList();
                foreach (var prod in ProdinfoList)
                {
                    var product = orderItemList.Where(i => i.ProductId == prod.ProductId).FirstOrDefault();
                    prod.UserId = afterSales.UserId;
                    prod.Status = 2;//出库

                    var flow = new StockFlowItem();
                    flow.UserId = modal.userId;
                    flow.CreateTime = dt;
                    flow.SheetNo = afterSales.AftersalesId;
                    flow.SnCode = prod.SnCode;
                    flow.ProductId = prod.ProductId;
                    flow.DbNo = "-";
                    flow.OrderType = 3;
                    flow.Price = 0;

                    flowList.Add(flow);

                }
                Context.Updateable<Prodinfo>(ProdinfoList).UpdateColumns(it => new { it.UserId, it.Status }).ExecuteCommand(); ;

                //写入库明细
                Context.Insertable<StockFlowItem>(flowList).ExecuteCommand();

                Update(u => u.AftersalesId == modal.afterSalesId, it => new Corecmsbillaftersales()
                {
                    ShipTime = DateTime.Now,
                    AfterProgress = 3,
                    //ConfirmStatus = 2,
                    //ConfirmTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                });

                modal.list.ForEach(code =>
                {
                    var exchange = new Exchangedetail();
                    exchange.OrderId = modal.orderId;
                    exchange.AftersalesId = modal.afterSalesId;
                    exchange.ProductId = code.ProductId;
                    exchange.SnCode = code.SnCode;
                    Exchangedetails.Add(exchange);
                });
                Context.Insertable<Exchangedetail>(Exchangedetails).ExecuteCommand();

                jm.status = true;
                jm.data = modal;
            });

            jm.status = result.IsSuccess;
            jm.msg = result.ErrorMessage;
            return jm;
        }

        /// <summary>
        /// 平台审核通过或者审核不通过
        /// 如果审核通过了，是退款单的话，自动生成退款单，并做订单完成状态，如果是退货的话，自动生成退款单和退货单，如果
        /// </summary>
        /// <param name="aftersalesId"></param>
        /// <param name="status"></param>
        /// <param name="type"></param>
        /// <param name="refund"></param>
        /// <param name="mark"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public async Task<WebApiCallBack> Audit(string aftersalesId, int status, int type, decimal refund, string mark,
            JArray items)
        {
            var jm = new WebApiCallBack();

            var res = await PreAudit(aftersalesId);
            if (!res.status)
            {
                return jm;
            }

            var info = res.data as Corecmsbillaftersales;
            var orderInfo = info.order;

            ////校验订单是否可以进行此售后，并且校验订单价格是否合理
            //var verifyData = Verify(info.Type, orderInfo, refund, items);
            //if (!verifyData.status && status == (int)BillAftersalesStatus.Success)
            //{
            //    return verifyData;
            //}


            ////如果订单未发货，那么用户不能选择已收到货
            //if (type == (int)BillAftersalesIsReceive.Reship &&
            //    orderInfo.ShipStatus == (int)OrderShipStatus.No)
            //{
            //    jm.msg = "收货才可以选择退货";//GlobalErrorCodeVars.Code13227;
            //    jm.code = 13227;
            //    return jm;
            //}

            ////如果是退货单，必须选择退货明细
            //if (info.Type == (int)BillAftersalesIsReceive.Reship && items.Count <= 0)
            //{
            //    jm.msg = "没有退货明细";//GlobalErrorCodeVars.Code13205;
            //    jm.code = 13205;
            //    return jm;
            //}

            ////如果是退货，判断退货明细，数量是否超出可退的数量
            var billAftersalesItems = new List<Corecmsbillaftersalesitem>();
            //if (items.Count > 0)
            //{
            //    var aftersalesItems = FormatAfterSalesItems(orderInfo, items, aftersalesId);
            //    if (!aftersalesItems.status)
            //    {
            //        return aftersalesItems;
            //    }

            //    billAftersalesItems = aftersalesItems.data as List<Corecmsbillaftersalesitem>;
            //}
            billAftersalesItems = info.Items;
            //判断退款金额不能超了
            if (refund + orderInfo.refunded > orderInfo.PayedAmount)
            {
                jm.msg = "退款金额大于付款金额";
                jm.code = 13206;
                return jm;
            }

            using (var container = _serviceProvider.CreateScope())
            {
                var itemServices = container.ServiceProvider.GetService<ICorecmsbillaftersalesitemService>();
                var orderServices = container.ServiceProvider.GetService<ICorecmsorderService>();
                var refundServices = container.ServiceProvider.GetService<ICorecmsbillrefundService>();
                var reshipServices = container.ServiceProvider.GetService<ICorecmsbillreshipService>();
                //var goodsServices = container.ServiceProvider.GetService<ICorecmsgoodsService>();
                var deatilServices = container.ServiceProvider.GetService<IBillaftersaledetailService>();
                var userServices = container.ServiceProvider.GetService<ICorecmsuserService>();
                var agentOrderServices = container.ServiceProvider.GetService<ICorecmsagentorderService>();

                var userModel = await userServices.GetFirstAsync(p => p.Id == orderInfo.UserId);



                ////更新售后单明细表，先删除，然后全新插入
                //await itemServices.DeleteAsync(p => p.AftersalesId == aftersalesId);
                //await deatilServices.DeleteAsync(p => p.AftersalesId == aftersalesId);

                //if (billAftersalesItems != null && billAftersalesItems.Any())
                //{
                //    await itemServices.InsertRangeAsync(billAftersalesItems);
                //    // 保存物码明细
                //    billAftersalesItems.ForEach(async t => {
                //        if (t.billaftersaledetails != null && t.billaftersaledetails.Count > 0)
                //        {
                //            await deatilServices.InsertRangeAsync(t.billaftersaledetails);

                //        }
                //    });
                //}


                //更新售后单
                int press = info.ReMethod == "1" ? 2 : 1;
                await UpdateAsync(p => new Corecmsbillaftersales() { Status = status, RefundAmount = refund, Type = type, AfterProgress = 2 },
                    p => p.AftersalesId == aftersalesId && p.Status == (int)BillAftersalesStatus.WaitAudit);

                //审核通过的话，有退款的，生成退款单，根据最新的items生成退货单,并做订单的状态更改
                if (status == (int)BillAftersalesStatus.Success)
                {
                    //如果有退款，生成退款单
                    if (refund > 0)
                    {
                        var refundRes = await refundServices.ToAdd(info.UserId, info.OrderId, orderInfo.OrderType, refund, info.AftersalesId);
                        if (!refundRes.status)
                        {
                            return refundRes;
                        }
                    }

                    /**不生成退货单**/
                    //如果已经发货了，要退货，生成退货单，邮寄退货模式让用户吧商品邮回来。
                    if (info.ReMethod == "0" && info.Type == (int)BillAftersalesIsReceive.Reship && billAftersalesItems != null && billAftersalesItems.Any())
                    {
                        var details = await deatilServices.GetListAsync(d => d.AftersalesId == info.AftersalesId);

                        var reshipRes = reshipServices.ToAdd(info.UserId, info.OrderId, info,
                            billAftersalesItems, details);
                        if (!reshipRes.status)
                        {
                            return reshipRes;
                        }
                    }
                    //更新订单状态


                    //判断货物发完没，如果货已发完了，订单发货就变成已发货,为了判断在有退款的情况下，当
                    var allDeliveryed = true;     //商品该发货状态，默认发货了,为了判断部分发货的情况下，的订单发货状态
                    var noDeliveryed = true;      //是否都没发货,默认都没发货
                    var allSened = true;          //商品退货状态（所有退货，包含已发的退货和未发的退货），默认都退货了,为了判断都退了的话，订单状态变成已完成

                    //foreach (var item in orderInfo.items)
                    //{
                    //    if (item.Id > 0)
                    //    {
                    //        foreach (var jToken in items)
                    //        {
                    //            var tt = (JObject)jToken;
                    //            if (tt["id"].ToString() == item.Id.ToString())
                    //            {
                    //                item.reshipNums += tt["nums"].ObjectToInt(0);
                    //                //判断 商品id相等，才能判断是否已发货，才能赋值给 reshipedNums 已发货的退货商品
                    //                if (type == (int)BillAftersalesIsReceive.Reship)
                    //                {
                    //                    item.reshipedNums += tt["nums"].ObjectToInt(0);
                    //                }
                    //            }
                    //        }
                    //    }
                    //    //有任何商品发货，都不是未发货状态
                    //    if (noDeliveryed && item.SendNums > 0)
                    //    {
                    //        noDeliveryed = false;
                    //    }

                    //    if (allDeliveryed && (item.Nums - item.SendNums - (item.reshipNums - item.reshipedNums) > 0))
                    //    {
                    //        //说明该发货的商品没发完
                    //        allDeliveryed = false;
                    //    }

                    //    if (allSened && (item.reshipNums < item.Nums))
                    //    {
                    //        //说明未退完商品
                    //        allSened = false;
                    //    }
                    //}

                    //if (allDeliveryed && !noDeliveryed)
                    //{
                    //    orderInfo.ShipStatus = (int)OrderShipStatus.Yes;
                    //}

                    //if (allSened)
                    //{
                    //    orderInfo.Status = (int)OrderStatus.Complete;
                    //}

                    //更新状态
                    //await orderServices.UpdateAsync(
                    //    p => new Corecmsorder() { Status = orderInfo.Status, PayStatus = orderInfo.PayStatus },
                    //    p => p.OrderId == orderInfo.OrderId);
                }

                //售后单审核过后的事件处理
                if (status == (int)BillAftersalesStatus.Success)
                {
                    //售后审核通过后处理
                    //await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.AfterSalesReview, aftersalesId);
                    //售后审核通过后积分退还机制
                    //await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.AfterSalesReviewForPoint, aftersalesId);
                }

            }

            orderInfo.addAftersalesStatus = true;
            orderInfo.BillAftersalesId = aftersalesId;
            orderInfo.Mark = mark;

            //发送售后审核消息
            // await _messageCenterServices.SendMessage(info.userId, GlobalEnumVars.PlatformMessageTypes.AfterSalesPass.ToString(), JObject.FromObject(orderInfo));

            jm.status = true;

            return jm;
        }


        #region 后端进行审核的时候，前置操作，1取出页面的数据，2在提交过来的表单的时候，进行

        /// <summary>
        /// 后端进行审核的时候，前置操作，1取出页面的数据，2在提交过来的表单的时候，进行校验
        /// </summary>
        /// <param name="aftersalesId"></param>
        /// <returns></return>
        public async Task<WebApiCallBack> PreAudit(string aftersalesId)
        {
            var jm = new WebApiCallBack();

            using var container = _serviceProvider.CreateScope();

            var userServices = container.ServiceProvider.GetService<ICorecmsuserService>();
            var imagesServices = container.ServiceProvider.GetService<ICorecmsbillaftersalesimagesService>();
            var itemServices = container.ServiceProvider.GetService<ICorecmsbillaftersalesitemService>();
            var orderServices = container.ServiceProvider.GetService<ICorecmsorderService>();

            var model = await GetFirstAsync(a => a.AftersalesId == aftersalesId);

            var userModel = await userServices.GetFirstAsync(p => p.Id == model.UserId);
            //model.userNickName = userModel != null ? userModel.nickName : "";
            // model.statusName = EnumHelper.GetEnumDescriptionByValue<BillAftersalesStatus>(model.Status);
            model.Images = await imagesServices.GetListAsync(p => p.AftersalesId == model.AftersalesId);
            model.Items = await itemServices.GetListAsync(p => p.AftersalesId == model.AftersalesId);

            //获取订单信息
            var orderResult = await orderServices.GetOrderInfoByOrderId(model.OrderId, model.UserId, 2);

            if (orderResult.status)
            {
                model.order = orderResult.data as Corecmsorder;

                //订单上的退款金额和数量只包含已经售后的，这里要把当次售后单的商品信息保存到订单
                // foreach (var orderItem in model.order.items)
                // {
                //orderItem.promotionList = string.Empty;
                //orderItem.atPresentReshipNums = 0;
                // foreach (var it in model.Items)
                // {
                //if (orderItem.Id == it.orderItemsId)
                //{
                //orderItem.atPresentReshipNums = it.nums;
                // }
                // }
                //}
            }
            jm.status = true;
            jm.data = model;


            return jm;
        }
        #endregion

        /// <summary>
        /// 根据订单号查询已经售后的内容
        /// </summary>
        /// <param name="orderId">订单编号</param>
        /// <param name="aftersaleLevel">取售后单的时候，售后单的等级，0：待审核的和审核通过的售后单，1未审核的，2审核通过的</param>
        /// <returns></returns>
        public WebApiCallBack OrderToAftersales(string orderId, int aftersaleLevel = 0)
        {
            var jm = new WebApiCallBack();

            List<int> statusInts = new List<int>();
            switch (aftersaleLevel)
            {
                case 0:
                    statusInts.Add((int)BillAftersalesStatus.Success);
                    statusInts.Add((int)BillAftersalesStatus.WaitAudit);
                    break;
                case 1:
                    statusInts.Add((int)BillAftersalesStatus.WaitAudit);
                    break;
                case 2:
                    statusInts.Add((int)BillAftersalesStatus.Success);
                    break;
                default:
                    jm.msg = "aftersale_level值类型不对";
                    return jm;
            }
            //算已经退过款的金额，取已经完成的售后单的金额汇总
            //加上待审核状态，这样申请过售后的商品和金额不会再重复申请了
            //已经退过款的金额
            var refundMoney = Queryable().Where(p => p.OrderId == orderId && p.SourceType == "0" && p.RetReasons != "3" && statusInts.Contains(p.Status)).Sum<decimal>(p => p.RefundAmount);

            //算退货商品明细
            var list = QueryMuch<Corecmsbillaftersalesitem, Corecmsbillaftersales, QMAfterSalesItems>(
                (child, parent) => new object[]
                {
                        JoinType.Inner, child.AftersalesId == parent.AftersalesId
                },
                (child, parent) => new QMAfterSalesItems
                {
                    orderItemsId = child.OrderItemsId,
                    nums = child.Nums,
                    status = parent.Status,
                    type = parent.Type
                }, (child, parent) => parent.OrderId == orderId && parent.SourceType == "0" && parent.RetReasons != "3" && statusInts.Contains(parent.Status));

            var reshipGoods = new Dictionary<int, reshipGoods>();
            if (list != null && list.Count > 0)
            {
                foreach (var item in list)
                {
                    var reshipGoodsItem = new reshipGoods()
                    {
                        reshipNums = 0,
                        reshipedNums = 0
                    };
                    reshipGoodsItem.reshipNums += item.nums;
                    if (item.type == (int)BillAftersalesIsReceive.Reship)
                    {
                        reshipGoodsItem.reshipedNums += item.nums;
                    }
                    if (reshipGoods.ContainsKey(item.orderItemsId)) 
                    {
                        reshipGoods[item.orderItemsId].reshipNums += reshipGoodsItem.reshipNums;
                        reshipGoods[item.orderItemsId].reshipedNums += reshipGoodsItem.reshipedNums;

                    }
                    else
                    {
                        reshipGoods.Add(item.orderItemsId, reshipGoodsItem);
                    }
                }
            }

            var billAftersales = Queryable().Where(p => p.OrderId == orderId && p.SourceType == "0" && p.RetReasons != "3" && statusInts.Contains(p.Status)).ToList();

            var orderIds = billAftersales.Select(it => it.AftersalesId).ToList();

            var afterSaleDetails = _billaftersaledetailService.Queryable().Where(d => orderIds.Contains(d.AftersalesId)).ToList();// _billaftersaledetailService.GetList(d=> orderIds.Contains(d.AftersalesId)); 
            jm.data = new OrderToAfterSalesDto
            {
                refundMoney = refundMoney,
                reshipGoods = reshipGoods,
                billAftersales = billAftersales,
                afterSaleDetails = afterSaleDetails
            };
            jm.status = true;
            jm.msg = jm.status ? "获取数据成功" : "获取数据失败！";

            return jm;
        }

        #region 创建售后单
        /// <summary>
        /// 创建售后单
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="orderId">发起售后的订单</param>
        /// <param name="type">是否收到退货，1未收到退货，不会创建退货单，2收到退货，会创建退货单,只有未发货的商品才能选择未收到货，只有已发货的才能选择已收到货</param>
        /// <param name="items">如果是退款退货，退货的明细 以 [[order_item_id=>nums]]的二维数组形式传值</param>
        /// <param name="images"></param>
        /// <param name="reason">售后理由</param>
        /// <param name="refund">退款金额，只在退款退货的时候用，如果是退款，直接就是订单金额</param>
        /// <returns></returns>
        public async Task<WebApiCallBack> ToAdd(long userId, string orderId, int type, JArray items, string[] images, string reason, decimal refund, string sourceType, string reMethod, string retReasons)
        {
            var jm = new WebApiCallBack();

            //做个简单校验，防止乱传值
            if (type != (int)BillAftersalesIsReceive.Refund && type != (int)BillAftersalesIsReceive.Reship)
            {
                jm.msg = "未定义的错误信息";
                jm.code = 10000;
                return jm;
            }


            //判断是否存在还未处理的售后单据。
            var haveAS = await IsAnyAsync(p => p.OrderId == orderId && p.UserId == userId && p.Status == (int)BillAftersalesStatus.WaitAudit);
            if (haveAS)
            {
                jm.msg = "存在未处理的售后单";
                jm.status = false;
                return jm;
            }
            var _corecmsorderService = App.GetService<ICorecmsorderService>();

            var orderInfo = await _corecmsorderService.GetFirstAsync(p => p.OrderId == orderId && p.UserId == userId);
            if (orderInfo == null)
            {
                jm.msg = "没有找到此订单信息,或者您没有权限查看此信息";
                jm.code = 13101;
                return jm;
            }
            orderInfo.items = await _corecmsorderitemService.GetListAsync(p => p.OrderId == orderInfo.OrderId);

            _corecmsorderService.AfterSalesVal(orderInfo);

            if (orderInfo.addAftersalesStatus == false)
            {
                jm.msg = "订单不是可售后状态";
                jm.code = 13200;
                return jm;
            }
            //生成售后单号
            var afterSalesId = CommonHelper.GetSerialNumberType((int)SerialNumberType.售后单编号);

            //校验订单是否可以进行此售后，并且校验订单价格是否合理
            var verifyResult = Verify(type, orderInfo, refund, items);
            if (verifyResult.status == false)
            {
                return verifyResult;
            }

            jm.otherData = new
            {
                orderInfo,
                items,
                verifyResult
            };

            //判断图片是否大于系统限定

            //var allConfigs = await settingServices.GetConfigDictionaries();
            if (images != null && images.Length > 9)
            {
                jm.msg = "图片超过限定张数";
                jm.code = 10006;
                return jm;
            }

            var aftersalesItemData = new List<Corecmsbillaftersalesitem>();
            if (items != null && items.Any())
            {
                //如果是退货，判断退货明细，数量是否超出可退的数量
                var aftersalesItems = FormatAfterSalesItems(orderInfo, items, afterSalesId);
                if (!aftersalesItems.status)
                {
                    return aftersalesItems;
                }
                //保存售后明细
                if (aftersalesItems.data != null)
                {
                    aftersalesItemData = aftersalesItems.data as List<Corecmsbillaftersalesitem>;
                }
                else
                {
                    jm.msg = "售后明细获取失败";
                    return jm;
                }
            }

            var billAftersales = new Corecmsbillaftersales();
            billAftersales.AftersalesId = afterSalesId;
            billAftersales.OrderId = orderId;
            billAftersales.UserId = userId;
            billAftersales.Type = type;
            billAftersales.RefundAmount = refund;
            billAftersales.Reason = reason;
            billAftersales.Status = (int)BillAftersalesStatus.WaitAudit;
            billAftersales.CreateTime = DateTime.Now;
            billAftersales.SourceType = sourceType;
            billAftersales.AfterProgress = 0;
            billAftersales.StoreId = orderInfo.StoreId;
            billAftersales.ReMethod = reMethod;
            billAftersales.RetReasons = retReasons;
            //保存主表数据
            await InsertAsync(billAftersales);

            await _corecmsbillaftersalesitemService.InsertRangeAsync(aftersalesItemData);

            //保存图片
            if (images != null && images.Length > 0)
            {

                var imagesList = new List<Corecmsbillaftersalesimages>();
                for (int i = 0; i < images.Length; i++)
                {
                    imagesList.Add(new Corecmsbillaftersalesimages()
                    {
                        AftersalesId = afterSalesId,
                        ImageUrl = images[i],
                        SortId = i
                    });
                }
                await _imageService.InsertRangeAsync(imagesList);
            }

            List<Billaftersaledetail> details = new List<Billaftersaledetail>();
            foreach (var item in aftersalesItemData)
            {
                details.AddRange(item.billaftersaledetails);
            }
            if (details.Count > 0)
            {
                _billaftersaledetailService.Deleteable().Where(it => it.AftersalesId == afterSalesId);
                await _billaftersaledetailService.InsertRangeAsync(details);
            }
            //Billaftersaledetail

            //消息模板推送给客户
            //SmsHelper.SendMessage();

            orderInfo.BillAftersalesId = afterSalesId;

            jm.status = true;
            jm.data = billAftersales;
            jm.msg = "售后申请成功！";
            return jm;
        }


        /// <summary>
        /// 代理售后申请
        /// </summary>
        /// 
        public async Task<WebApiCallBack> ToAddUn(long userId, int type, List<Corecmsbillaftersalesitem> items, string[] images, string reason, decimal refund, string sourceType, List<Prodinfo> details)
        {
            var jm = new WebApiCallBack();

            var productIds = items.Select(oi => oi.ProductId).ToList();
            var userStockList = Context.Queryable<Corecmsuserstock>().Where(p => p.UserId == userId && productIds.Contains(p.ProductId)).ToList();
            var result = UseTran(() =>
            {
                var _corecmsorderService = App.GetService<ICorecmsorderService>();

                var afterSalesNew = new Corecmsbillaftersales();
                afterSalesNew.AftersalesId = CommonHelper.GetSerialNumberType((int)SerialNumberType.售后单编号);
                afterSalesNew.UserId = userId;
                afterSalesNew.Status = (int)BillAftersalesStatus.Success;
                afterSalesNew.CreateTime = DateTime.Now;
                afterSalesNew.SourceType = "1";
                afterSalesNew.AfterProgress = 5;
                afterSalesNew.RetReasons = "2";
                afterSalesNew.ReMethod = "1";
                afterSalesNew.OrderId = " ";
                afterSalesNew.RefundAmount = 0;

                var orderItemDetailsNew = new List<Billaftersaledetail>();
                details.ForEach(item =>
                {
                    afterSalesNew.RefundAmount+= item.CostPrice.HasValue?item.CostPrice.Value:0;

                    var orderDetailNew = new Billaftersaledetail();
                    orderDetailNew.AftersalesId = afterSalesNew.AftersalesId;
                    orderDetailNew.SnCode = item.SnCode;
                    orderDetailNew.ProductId = item.ProductId;
                    orderItemDetailsNew.Add(orderDetailNew);
                    Context.Updateable<Prodinfo>().SetColumns(it => new Prodinfo { Status = 2 }).Where(it => it.SnCode == item.SnCode).ExecuteCommand();
                });

                //代理滞销退货 需要处理库存和铺货数量
                items.ForEach(item =>
                {
                    item.AftersalesId = afterSalesNew.AftersalesId;
                    item.CreateTime = afterSalesNew.CreateTime;
                    var us = userStockList.Find(us => us.ProductId == item.ProductId);
                    if (us != null)
                    {
                        us.Stock -= item.Nums;
                        us.SaleStock -= item.Nums;
                        us.PurStock -= item.Nums;
                    }
                    if (us.Stock < 0) us.Stock = 0;
                    if (us.SaleStock < 0) us.SaleStock = 0;
                    if (us.PurStock < 0) us.PurStock = 0;

                });

                Context.Updateable<Corecmsuserstock>(userStockList).WhereColumns(it => new { it.Id }).UpdateColumns(it => new { it.Stock, it.SaleStock, it.PurStock }).ExecuteCommand();

                Context.Insertable<Corecmsbillaftersalesitem>(items).ExecuteCommand();

                Context.Insertable<Billaftersaledetail>(orderItemDetailsNew).ExecuteCommand();

                Context.Insertable<Corecmsbillaftersales>(afterSalesNew).ExecuteCommand();

                if (images != null && images.Length > 0)
                {
                    List<Corecmsbillaftersalesimages> imgs = new List<Corecmsbillaftersalesimages>();

                    foreach (var item in images)
                    {
                        Corecmsbillaftersalesimages image = new Corecmsbillaftersalesimages();
                        image.AftersalesId = afterSalesNew.AftersalesId;
                        image.ImageUrl = item;
                        image.SortId = 0;

                        imgs.Add(image);
                    }

                    _imageService.InsertRange(imgs);
                }
            });
            jm.status = result.IsSuccess;
            jm.data = items;
            jm.msg = result.ErrorMessage;
            return jm;
        }


        #endregion

        #region 校验是否可以进行售后
        /// <summary>
        /// 校验是否可以进行售后
        /// </summary>
        /// <param name="type"></param>
        /// <param name="orderInfo"></param>
        /// <param name="refund"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        private WebApiCallBack Verify(int type, Corecmsorder orderInfo, decimal refund, JArray items)
        {
            var jm = new WebApiCallBack();
            //判断订单是否是可以售后
            //只有活动订单才能售后
            if (orderInfo.Status == (int)OrderStatus.Cancel)
            {
                jm.msg = "订单不是可售后状态";
                jm.code = 13200;
                return jm;
            }
            //未付款订单和已退款订单不能售后
            if (orderInfo.PayStatus == (int)OrderPayStatus.No || orderInfo.PayStatus == (int)OrderPayStatus.Refunded)
            {
                jm.msg = "订单状态不可退款";
                jm.code = 13203;
                return jm;
            }
            //如果订单未发货，那么用户不能选择已收到货
            if (type == (int)BillAftersalesIsReceive.Reship && orderInfo.ShipStatus == (int)OrderShipStatus.No)
            {
                jm.msg = "还没发货呢，怎么能收到货呢？";
                jm.code = 13227;
                return jm;
            }
            //判断退款金额不能超
            if (refund + orderInfo.refunded > orderInfo.PayedAmount)
            {
                jm.msg = "总退款金额超过已支付金额";
                jm.code = 13206;
                return jm;
            }
            //根据是否已收到货和未收到货来判断实际可以退的数量，不能超过最大数量，已收到货的和未收到货的不能一起退，在这里做判断
            return verifyNums(type, orderInfo, items);
        }
        #endregion

        #region 根据退货的明细，生成售后单明细表的数据
        /// <summary>
        /// 根据退货的明细，生成售后单明细表的数据
        /// </summary>
        /// <param name="orderInfo">订单的详细数据</param>
        /// <param name="items">前台选择的退货商品信息</param>
        /// <param name="aftersalesId">将要保存的售后单的单号</param>
        /// <returns></returns>
        private WebApiCallBack FormatAfterSalesItems(Corecmsorder orderInfo, JArray items, string aftersalesId)
        {
            var jm = new WebApiCallBack();
            var data = new List<Corecmsbillaftersalesitem>();
            foreach (var item in items)
            {
                var id = ((JObject)item)["id"].ObjectToInt();
                var nums = ((JObject)item)["nums"].ObjectToInt();
                var details = ((JObject)item)["snCodes"].ObjectToString();

                if (nums < 0)
                {
                    continue;
                }

                foreach (var orderItem in orderInfo.items)
                {
                    if (orderItem.Id == id)
                    {
                        //判断已经退过的加上本次退的，是否超过了购买的数量,具体取nums（购买数量）还是取sendnums(已发货数量),以后再说吧。要取购买数量，因为未发货的，也可以退的
                        if (nums + orderItem.reshipNums > orderItem.Nums)
                        {
                            jm.msg = "退货的数量超过可退的数量";
                            jm.code = 13201;
                            return jm;
                        }
                        var billAftersalesItem = new Corecmsbillaftersalesitem
                        {
                            AftersalesId = aftersalesId,
                            OrderItemsId = orderItem.Id,
                            GoodsId = orderItem.GoodsId,
                            ProductId = orderItem.ProductId,
                            Sn = orderItem.Sn,
                            Bn = orderItem.Bn,
                            Name = orderItem.Name,
                            ImageUrl = orderItem.ImageUrl,
                            Nums = nums,
                            Price = orderItem.Price,
                            Amount = orderItem.Price * nums,
                            Addon = orderItem.Addon,
                            CreateTime = DateTime.Now,
                            billaftersaledetails = new List<Billaftersaledetail>()
                        };
                        var arr = details.Split(',');
                        if (arr != null)
                        {
                            foreach (var item1 in arr)
                            {
                                var detail = new Billaftersaledetail
                                {
                                    AftersalesId = aftersalesId,
                                    ProductId = orderItem.ProductId,
                                    SnCode = item1
                                };

                                billAftersalesItem.billaftersaledetails.Add(detail);
                            }
                        }

                        data.Add(billAftersalesItem);
                    }
                }
            }
            //判断生成的总记录条数，是否和前端传过来的记录条数对应上，如果没有对应上，就说明退货明细不正确
            if (data.Count != items.Count)
            {
                jm.msg = "退货商品不正确，请确认";
                jm.data = jm.code = 13202;
                return jm;
            }
            jm.status = true;
            jm.data = data;
            return jm;
        }

        #endregion

        #region 判断退货数量是否超标
        /// <summary>
        /// 判断退货数量是否超标
        /// </summary>
        /// <param name="type"></param>
        /// <param name="orderInfo"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        private WebApiCallBack verifyNums(int type, Corecmsorder orderInfo, JArray items)
        {
            var jm = new WebApiCallBack();
            foreach (var item in items)
            {
                var id = ((JObject)item)["id"].ObjectToInt();
                var nums = ((JObject)item)["nums"].ObjectToInt();

                foreach (var orderItem in orderInfo.items)
                {
                    if (orderItem.Id == id)
                    {
                        if (type == (int)BillAftersalesIsReceive.Refund)
                        {
                            //售后中未退换的数量（申请售后退还的，已经收到退还的，差额就是客户还需要退还的）
                            var reshipNum = orderItem.reshipNums - orderItem.reshipedNums;

                            //如果未发货，但申请售后大于0
                            if (orderItem.SendNums == 0 && nums > 0)
                            {
                                jm.msg = orderItem.Name + orderItem.Addon + "，未发货商品，退货数量只能为0个";
                                return jm;
                            }
                            //如果当前售后数量+未寄送的售后数量 > 已经发货数量
                            if (reshipNum + nums > orderItem.SendNums)
                            {
                                jm.msg = orderItem.Name + orderItem.Addon + "，售后申请超过数量，最多能退" + (orderItem.SendNums - reshipNum - nums) + "个";
                                return jm;
                            }
                        }
                        else
                        {
                            var n = orderItem.SendNums - orderItem.reshipedNums;
                            if (n < nums)
                            {
                                jm.msg = orderItem.Name + orderItem.Addon + "已发货商品，最多能退" + n + "个";
                                return jm;
                            }
                        }
                    }
                }
            }
            jm.status = true;
            return jm;
        }
        #endregion

        /// <summary>
        /// 查询导出表达式
        /// </summary>
        /// <param name="parm"></param>
        /// <returns></returns>
        private static Expressionable<Corecmsbillaftersales> QueryExp(CorecmsbillaftersalesQueryDto parm)
        {
            var predicate = Expressionable.Create<Corecmsbillaftersales>();

            predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.OrderId), it => it.OrderId == parm.OrderId || it.AftersalesId == parm.OrderId);
            predicate = predicate.AndIF(parm.BeginCreateTime == null, it => it.CreateTime >= DateTime.Now.AddDays(-90).ToShortDateString().ParseToDateTime());
            predicate = predicate.AndIF(parm.BeginCreateTime != null, it => it.CreateTime >= parm.BeginCreateTime);
            predicate = predicate.AndIF(parm.EndCreateTime != null, it => it.CreateTime <= parm.EndCreateTime);
            if (!string.IsNullOrEmpty(parm.SourceType))
            {
                predicate = predicate.And(it => it.SourceType == parm.SourceType);
            }
            else
            {
                predicate = predicate.And(it => it.SourceType == "0");
            }
            if (parm.SourceType == "1")
            {
                predicate = predicate.And(it => it.User.Id == parm.userId);
            }
            else
            {
                predicate = predicate.And(it => it.User.ParentId == parm.userId);
            }
            if (parm.Status.HasValue)
            {
                if (parm.Status == 0)
                {
                    predicate = predicate.And(it => it.Status == 1);
                }
                else
                {
                    predicate = predicate.And(it => it.AfterProgress == parm.Status);

                }
            }
            return predicate;
        }

        /// <summary>
        /// 查询导出表达式
        /// </summary>
        /// <param name="parm"></param>
        /// <returns></returns>
        private static Expressionable<Corecmsbillaftersales> QueryStockExp(AfterStockQueryDto parm)
        {
            var predicate = Expressionable.Create<Corecmsbillaftersales>();

            predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.OrderId), it => it.OrderId == parm.OrderId);
            predicate = predicate.AndIF(parm.BeginCreateTime == null, it => it.CreateTime >= DateTime.Now.AddDays(-365).ToShortDateString().ParseToDateTime());
            predicate = predicate.AndIF(parm.BeginCreateTime != null, it => it.CreateTime >= parm.BeginCreateTime);
            predicate = predicate.AndIF(parm.EndCreateTime != null, it => it.CreateTime <= parm.EndCreateTime);
            if (!string.IsNullOrEmpty(parm.SourceType))
            {
                predicate = predicate.And(it => it.SourceType == parm.SourceType);
            }
            else
            {
                predicate = predicate.And(it => it.SourceType == "0");
            }
            if (parm.SourceType == "1")
            {
                predicate = predicate.And(it => it.User.Id == parm.userId);
            }
            else
            {
                predicate = predicate.And(it => it.User.ParentId == parm.userId);
            }

            return predicate;
        }
    }
}